home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / langs / dumpaout.lzh / DUMPAOUT.C next >
Encoding:
C/C++ Source or Header  |  1993-06-19  |  14.3 KB  |  477 lines

  1. /*****************************************************************************
  2.  * DUMPAOUT - Dump data about a GNU a.out-format object module.
  3.  *
  4.  *          This is a simple utility without a lot of bells and whistles.
  5.  *          Throw a bogus or broken a.out file at it and it'll probably
  6.  *          crash.  I wrote it mainly to help me determine that I had the
  7.  *          HSC JAS assembler properly emitting regulation a.out modules.
  8.  *
  9.  *          GEMDOS file I/O and memory allocation is used, not because I
  10.  *          have anything against runtime libraries so much as that it
  11.  *          provides independence from size_t/int/long portability issues.
  12.  *
  13.  *          This file is self-contained; there are no other source modules
  14.  *          or header files other than standard compiler headers.  It was
  15.  *          written for HSC, and doesn't contain prototypes.
  16.  *
  17.  *          Don't let the appearance of the term 'GNU' fool you:  this is
  18.  *          public domain software, free of any encumbrances whatsoever.
  19.  *          There are no facist restrictions on copying or using this code
  20.  *          in any way you see fit.
  21.  *
  22.  * 06/16/93 v1.0 (Ian Lepore)
  23.  *          Created.
  24.  *****************************************************************************/
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <stdarg.h>
  29. #include <osbind.h>
  30.  
  31. #ifndef TRUE
  32.   #define TRUE  1
  33.   #define FALSE 0
  34. #endif
  35.  
  36. #ifdef __BORLANDC__     /* %@#!^@%#$@# Borland compiler won't define    */
  37.   #define __STDC__      /* __STDC__ unless you ask for Pure-ANSI mode.  */
  38. #endif                  /* (And nothing works right in its Pure-ANSI.)  */
  39.  
  40. /*----------------------------------------------------------------------------
  41.  *  structures and constants used with a.out modules.
  42.  *    cobbled together from the manpage for a.out on a Sun system,
  43.  *    mainly by deleting massive amounts of unneeded (by me) stuff.
  44.  *--------------------------------------------------------------------------*/
  45.  
  46. typedef struct {                /* a.out module file header... */
  47.   unsigned long     a_info;     /* typical magic value identifies file */
  48.   unsigned long     a_text;     /* length of text, in bytes */
  49.   unsigned long     a_data;     /* length of data, in bytes */
  50.   unsigned long     a_bss;      /* length of uninitialized data area in bytes */
  51.   unsigned long     a_syms;     /* length of symbol table data in bytes */
  52.   unsigned long     a_entry;    /* start address (unused in object modules) */
  53.   unsigned long     a_trsize;   /* length of relocation info for text, in bytes */
  54.   unsigned long     a_drsize;   /* length of relocation info for data, in bytes */
  55. } EXEC;
  56.  
  57. #define A_OUT_MAGIC 0407        /* value of exec.a_info for object module */
  58.  
  59. typedef struct {                /* symbol for a.out file... */
  60.   long              n_strx;
  61.   unsigned char     n_type;
  62.   char              n_other;
  63.   short             n_desc;
  64.   unsigned long     n_value;
  65. } NLIST;
  66.  
  67. #define N_UNDF      0           /* symbol n_type flag values... */
  68. #define N_EXT       1
  69. #define N_ABS       2
  70. #define N_TEXT      4
  71. #define N_DATA      6
  72. #define N_BSS       8
  73. #define N_FN       15
  74. #define N_COMM     18
  75.  
  76. typedef struct {                /* reloc directive for a.out file... */
  77.   unsigned long     r_address;
  78.   unsigned long     r_symboldat;
  79. } RINFO;
  80.  
  81. #define RINFO_PCREL 0x80        /* values ORed into low byte of */
  82. #define RINFO_LONG  0x40        /* rinfo.r_symboldat */
  83. #define RINFO_WORD  0x20
  84. #define RINFO_EXT   0x10
  85.  
  86. /*----------------------------------------------------------------------------
  87.  * internal data.
  88.  *--------------------------------------------------------------------------*/
  89.  
  90. static EXEC  thehdr;
  91. static short inhandle;
  92. static char  *fname;
  93. static char  *strtab;
  94. static NLIST *symtab;
  95.  
  96. static char  *text;
  97. static char  *data;
  98.  
  99. static long  nsyms;
  100. static long  ntrelocs;
  101. static long  ndrelocs;
  102.  
  103. static long  toffset;
  104. static long  doffset;
  105. static long  treloffset;
  106. static long  dreloffset;
  107. static long  symoffset;
  108. static long  stroffset;
  109.  
  110. /*----------------------------------------------------------------------------
  111.  * code.
  112.  *--------------------------------------------------------------------------*/
  113.  
  114. #ifdef __STDC__
  115.   void fatal(char *,...);
  116.   void gfree(void *);
  117.   void *emalloc(long);
  118.   void read_error(char *);
  119.   void load_show_header(void);
  120.   void load_text(void);
  121.   void load_data(void);
  122.   void load_symbol_data(void);
  123.   void show_a_symbol(NLIST *);
  124.   void load_show_symbol_table(void);
  125.   void show_a_reloc(RINFO *,char *);
  126.   void load_show_reloc(char *,char *,long,long);
  127.   void load_show_file(char *);
  128.   int main(int,char **);
  129. #endif
  130.  
  131. /*----------------------------------------------------------------------------
  132.  * service routines.
  133.  *--------------------------------------------------------------------------*/
  134.  
  135. #ifdef __STDC__
  136.   static void fatal(char *fmt, ...)
  137. #else
  138.   static void fatal(fmt)
  139.     char *fmt;
  140. #endif
  141. /*****************************************************************************
  142.  * whine and die.
  143.  ****************************************************************************/
  144. {
  145.     va_list args;
  146.  
  147.     fputs("dumpaout (fatal): ", stderr);
  148.     va_start(args, fmt);
  149.     vfprintf(stderr, fmt, args);
  150.     va_end(args);
  151.     fputc('\n', stderr);
  152.     exit(1);
  153. }
  154.  
  155. static void gfree(block)
  156.     void *block;
  157. /*****************************************************************************
  158.  * gentle-free; free the block if the pointer is non-NULL.
  159.  ****************************************************************************/
  160. {
  161.     if (block) {
  162.         Mfree(block);
  163.     }
  164. }
  165.  
  166. static void *emalloc(size)
  167.     long size;
  168. /*****************************************************************************
  169.  * allocate a block; whine and die if it fails.
  170.  ****************************************************************************/
  171. {
  172.     void *block;
  173.  
  174.     if (NULL == (block = (void*)Malloc(size))) {
  175.         fatal("out of memory processing file %s, asked for %ld", fname, size);
  176.     }
  177.     return block;
  178. }
  179.  
  180. static void read_error(type)
  181.     char *type;
  182. /*****************************************************************************
  183.  *
  184.  ****************************************************************************/
  185. {
  186.     fatal("Error reading %s on file %s\n", type, fname);
  187. }
  188.  
  189. static void load_show_header()
  190. /*****************************************************************************
  191.  *
  192.  ****************************************************************************/
  193. {
  194.     register EXEC *h = &thehdr;
  195.  
  196.     if (sizeof(EXEC) != Fread(inhandle, (long)sizeof(EXEC), h)) {
  197.         read_error("header");
  198.     }
  199.  
  200.     nsyms    = h->a_syms   / sizeof(NLIST);
  201.     ntrelocs = h->a_trsize / sizeof(RINFO);
  202.     ndrelocs = h->a_drsize / sizeof(RINFO);
  203.  
  204.     toffset    = sizeof(EXEC);
  205.     doffset    = toffset    + h->a_text;
  206.     treloffset = doffset    + h->a_data;
  207.     dreloffset = treloffset + h->a_trsize;
  208.     symoffset  = dreloffset + h->a_drsize;
  209.     stroffset  = symoffset  + h->a_syms;
  210.  
  211.     printf("Header for file %s...\n"
  212.            "  a_info                  = %08lX\n"
  213.            "  Text size               = %08lX\n"
  214.            "  Data size               = %08lX\n"
  215.            "  BSS size                = %08lX\n"
  216.            "  Sym size, count         = %08lX, %5ld\n"
  217.            "  Text reloc size, count  = %08lX, %5ld\n"
  218.            "  Data reloc size, count  = %08lX, %5ld\n"
  219.            "\n",
  220.            fname,
  221.            h->a_info,
  222.            h->a_text,
  223.            h->a_data,
  224.            h->a_bss,
  225.            h->a_syms,   nsyms,
  226.            h->a_trsize, ntrelocs,
  227.            h->a_drsize, ndrelocs
  228.           );
  229.  
  230.     if (A_OUT_MAGIC != (h->a_info & 0x0000FFFF)) {
  231.         fatal("Bad magic in %s file header", fname);
  232.     }
  233.  
  234. }
  235.  
  236. static void load_text()
  237. /*****************************************************************************
  238.  *
  239.  ****************************************************************************/
  240. {
  241.     if (thehdr.a_text == 0) {
  242.         return;
  243.     }
  244.     text = emalloc(thehdr.a_text);
  245.     Fseek(toffset, inhandle, SEEK_SET);
  246.     if (thehdr.a_text != Fread(inhandle, thehdr.a_text, text)) {
  247.         read_error("text segment");
  248.     }
  249. }
  250.  
  251. static void load_data()
  252. /*****************************************************************************
  253.  *
  254.  ****************************************************************************/
  255. {
  256.     if (thehdr.a_data == 0) {
  257.         return;
  258.     }
  259.     data = emalloc(thehdr.a_data);
  260.     Fseek(doffset, inhandle, SEEK_SET);
  261.     if (thehdr.a_data != Fread(inhandle, thehdr.a_data, data)) {
  262.         read_error("data segment");
  263.     }
  264. }
  265.  
  266. static void load_symbol_data()
  267. /*****************************************************************************
  268.  *
  269.  ****************************************************************************/
  270. {
  271.     long    strtabsize;
  272.  
  273.     if (thehdr.a_syms == 0) {
  274.         return;
  275.     }
  276.  
  277.     Fseek(stroffset, inhandle, SEEK_SET);
  278.     if (sizeof(strtabsize) != Fread(inhandle, (long)sizeof(strtabsize), &strtabsize)) {
  279.         read_error("string table size");
  280.     }
  281.  
  282.     symtab = emalloc(thehdr.a_syms);
  283.     strtab = emalloc(strtabsize);
  284.  
  285.     Fseek(symoffset, inhandle, SEEK_SET);
  286.     if (thehdr.a_syms != Fread(inhandle, thehdr.a_syms, symtab)) {
  287.         read_error("symbol table");
  288.     }
  289.     if (strtabsize != Fread(inhandle, strtabsize, strtab)) {
  290.         read_error("string table");
  291.     }
  292. }
  293.  
  294. static void show_a_symbol(sym)
  295.     register NLIST *sym;
  296. /*****************************************************************************
  297.  *
  298.  ****************************************************************************/
  299. {
  300.     char *symname;
  301.     char *symscope;
  302.     char *symtype;
  303.  
  304.     if (sym->n_strx == 0) {
  305.         symname = "<No Name>";
  306.     } else {
  307.         symname = &strtab[sym->n_strx];
  308.     }
  309.  
  310.     symscope = (sym->n_type & N_EXT) ? "EXT " : "    ";
  311.  
  312.     switch (sym->n_type & 0x00FE) {
  313.       case N_ABS:   symtype = "ABS  "; break;
  314.       case N_TEXT:  symtype = "TEXT "; break;
  315.       case N_DATA:  symtype = "DATA "; break;
  316.       case N_BSS:   symtype = "BSS  "; break;
  317.       case N_FN:    symtype = "FNAM "; break;
  318.       default:      symtype = "UNKN "; break;
  319.     }
  320.  
  321.     printf("  %-24s %s%s %08lX\n", symname, symscope, symtype, sym->n_value);
  322. }
  323.  
  324. static void load_show_symbol_table()
  325. /*****************************************************************************
  326.  *
  327.  ****************************************************************************/
  328. {
  329.     long i;
  330.  
  331.     load_symbol_data();
  332.  
  333.     printf("Symbol table for file %s\n", fname);
  334.  
  335.     if (thehdr.a_syms == 0) {
  336.         printf("<no symbols in file>\n");
  337.         return;
  338.     }
  339.  
  340.     for (i = 0; i < nsyms; ++i) {
  341.         show_a_symbol(&symtab[i]);
  342.     }
  343.  
  344.     printf("\n");
  345. }
  346.  
  347. static void show_a_reloc(rinfo, segaddr)
  348.     register RINFO *rinfo;
  349.     char           *segaddr;
  350. /*****************************************************************************
  351.  *
  352.  ****************************************************************************/
  353. {
  354.     unsigned char flags;
  355.     unsigned long symnum;
  356.     unsigned long segvalue;
  357.     char          *type;
  358.     char          *size;
  359.  
  360.     flags  = rinfo->r_symboldat & 0x000000FF;
  361.     symnum = rinfo->r_symboldat >> 8;
  362.  
  363.     switch (flags & (RINFO_LONG|RINFO_WORD)) {
  364.       case RINFO_LONG:
  365.         size = "LONG";
  366.         segvalue = *(unsigned long *)(segaddr+rinfo->r_address);
  367.         break;
  368.       case RINFO_WORD:
  369.         size = "WORD";
  370.         segvalue = *(unsigned short *)(segaddr+rinfo->r_address);
  371.         break;
  372.       default:
  373.         size = "BYTE";
  374.         segvalue = *(unsigned char *)(segaddr+rinfo->r_address);
  375.         break;
  376.     }
  377.  
  378.     if (flags & RINFO_PCREL) {
  379.         type = "PC";
  380.     } else {
  381.         type = "  ";
  382.     }
  383.  
  384.     printf("  %08lX %s %s =%08lX ", rinfo->r_address, size, type, segvalue);
  385.  
  386.     if (flags & RINFO_EXT) {
  387.         if (symnum > nsyms) {
  388.             printf("?? reference to symbol # %ld of %ld syms in file ??\n",
  389.                     symnum, nsyms);
  390.         } else {
  391.             printf("SYM =");
  392.             show_a_symbol(&symtab[symnum]);
  393.         }
  394.     } else {
  395.         switch (symnum & 0x000000FE) {
  396.           case N_TEXT: type = "TEXT"; break;
  397.           case N_DATA: type = "DATA"; break;
  398.           case N_BSS:  type = "BSS "; break;
  399.           default:     type = "UNKN"; break;
  400.         }
  401.         printf("SEG = %s\n", type, symnum);
  402.     }
  403. }
  404.  
  405. static void load_show_reloc(segname, segaddr, offset, count)
  406.     char *segname;
  407.     char *segaddr;
  408.     long offset;
  409.     long count;
  410. /*****************************************************************************
  411.  *
  412.  ****************************************************************************/
  413. {
  414.     long  i;
  415.     RINFO rinfo;
  416.  
  417.     printf("%s segment relocation info for file %s\n", segname, fname);
  418.     Fseek(offset, inhandle, SEEK_SET);
  419.     for (i = 0; i < count; ++i) {
  420.         if (sizeof(rinfo) != Fread(inhandle, (long)sizeof(rinfo), &rinfo)) {
  421.             read_error("relocation data");
  422.         }
  423.         show_a_reloc(&rinfo, segaddr);
  424.     }
  425.     printf("\n");
  426. }
  427.  
  428. static void load_show_file(name)
  429.     char *name;
  430. /*****************************************************************************
  431.  *
  432.  ****************************************************************************/
  433. {
  434.     fname = name;
  435.  
  436.     if (0 > (inhandle = Fopen(name, 0))) {
  437.         fatal("Can't open file %s\n", name);
  438.     }
  439.  
  440.     load_show_header();
  441.     load_text();
  442.     load_data();
  443.     load_show_symbol_table();
  444.     load_show_reloc("TEXT", text, treloffset, ntrelocs);
  445.     load_show_reloc("DATA", data, dreloffset, ndrelocs);
  446.     printf("\n");
  447.  
  448.     gfree(symtab);
  449.     gfree(strtab);
  450.     gfree(data);
  451.     gfree(text);
  452.     Fclose(inhandle);
  453. }
  454.  
  455. int main(argc, argv)
  456.     int  argc;
  457.     char **argv;
  458. /*****************************************************************************
  459.  *
  460.  ****************************************************************************/
  461. {
  462.     if (argc < 2) {
  463.         fputs("usage: DUMPAOUT file [file...]\n"
  464.               "\n"
  465.               "Displays header, symbol, and relocation info from\n"
  466.               "one or more GNU a.out object modules.\n"
  467.               ,stderr);
  468.         exit(1);
  469.     }
  470.  
  471.     while (--argc) {
  472.         load_show_file(*++argv);
  473.     }
  474.  
  475.     return 0;
  476. }
  477.